package org.ala.tcp_feign_server.handler.biz;

import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

import org.ala.tcp_feign_common.config.AttrbuteKeyNamespace;
import org.ala.tcp_feign_common.enums.TcpFeignBizAckTypeEnums;
import org.ala.tcp_feign_common.enums.TcpFeignMessageTypeEnums;
import org.ala.tcp_feign_common.exceptions.RemoteInvokeException;
import org.ala.tcp_feign_common.exceptions.SerializableException;
import org.ala.tcp_feign_common.handler.IByteMessageAction;
import org.ala.tcp_feign_common.logs.LoggerFactory;
import org.ala.tcp_feign_common.msg.biz.BizACKByteMessage;
import org.ala.tcp_feign_common.msg.biz.BizByteMessage;
import org.ala.tcp_feign_common.msg.biz.body.BizBody;
import org.ala.tcp_feign_common.msg.biz_resp.BizRespByteMessage;
import org.ala.tcp_feign_common.msg.biz_resp.body.BizRespBody;
import org.ala.tcp_feign_server.context.TcpFeignServerContext;
import org.ala.tcp_feign_server.context.executor.TcpFeignServerExecutor;
import org.slf4j.Logger;

import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;


/**
 * 业务消息action
 *
 * @author 骆毅(ala)
 * @date 2024年4月19日
 */
public class BizByteMessageAction implements IByteMessageAction<BizByteMessage> {
	
	
	static Logger log = LoggerFactory.getLogger("tcp-feign", "server");
	

	@Override
	public TcpFeignMessageTypeEnums type() {
		return TcpFeignMessageTypeEnums.BIZ;
	}
	

	@Override
	public void action(ChannelHandlerContext ctx, BizByteMessage msg) {
		//	检测登录
		if (ctx.channel().attr(AttributeKey.valueOf(AttrbuteKeyNamespace.LOGIN)).get() == null) {
			ctx.writeAndFlush(BizACKByteMessage.faild(msg.getMsgId(), TcpFeignBizAckTypeEnums.NO_LOGIN));
			return;
		}
		//	body反序列化为BizBody
		try {
			BizBody body = TcpFeignServerContext.instance().getSerializabler().deSerialize(msg.getBody(), BizBody.class);
			
			//	找到执行业务逻辑的Executor
			TcpFeignServerExecutor executor = TcpFeignServerContext.instance().getExecutorMapper().getExecutor(body.getUrl());
			if (executor == null) {
				log.error("[BizByteMessageAction action] 无法找到消息对应的executor msgId:" + msg.getMsgId() + " url:" + body.getUrl());
				ctx.writeAndFlush(BizACKByteMessage.faild(msg.getMsgId(), TcpFeignBizAckTypeEnums.NO_METHOD));
				return;
			}
			//	线程池执行executor
			ThreadPoolExecutor threadPool = TcpFeignServerContext.instance().getExecutorThreadPool().getExecutorThreadPool(executor.getBean());
			
			//	用线程池执行任务
			try {
				threadPool.execute(() -> {
					try {
						//	执行任务，拿返回值
						Object result = executor.invoke(body.getArgs());
						byte[] resultBody = TcpFeignServerContext.instance().getSerializabler().serialize(BizRespBody.build(body.getUrl(), result));
						//	给回执（在netty的线程模型内顺序执行）
						ctx.channel().eventLoop().execute(() -> ctx.channel().writeAndFlush(BizRespByteMessage.success(msg.getMsgId(), resultBody)));
					} catch (RemoteInvokeException e) {
						ctx.channel().eventLoop().execute(() -> ctx.channel().writeAndFlush(BizRespByteMessage.faild(msg.getMsgId())));
						log.error("[BizByteMessageAction action] 执行业务逻辑异常 " + e.getMessage(), e);
					} catch (SerializableException e) {
						ctx.channel().eventLoop().execute(() -> ctx.channel().writeAndFlush(BizRespByteMessage.faild(msg.getMsgId())));
						log.error("[BizByteMessageAction action] 执行业务逻辑成功，但返回值序列化异常 " + e.getMessage(), e);
					}
				});
			} catch (RejectedExecutionException e) {
				log.error("[BizByteMessageAction action] 线程池满 msgId:" + msg.getMsgId() + " url:" + body.getUrl());
				ctx.writeAndFlush(BizACKByteMessage.faild(msg.getMsgId(), TcpFeignBizAckTypeEnums.NO_THREAD));
			}
			
			//	给个回执
			ctx.writeAndFlush(BizACKByteMessage.success(msg.getMsgId()));
		} catch (SerializableException e) {
			log.error("[BizByteMessageAction action] 消息序列化异常 " + e.getMessage(), e);
			ctx.writeAndFlush(BizACKByteMessage.faild(msg.getMsgId(), TcpFeignBizAckTypeEnums.SERIA_ERROR));
		} catch (Exception e) {
			log.error("[BizByteMessageAction action] 执行任务失败 " + e.getMessage(), e);
			ctx.writeAndFlush(BizACKByteMessage.faild(msg.getMsgId(), TcpFeignBizAckTypeEnums.FAILD));
		}
	}

}
